/**
  ******************************************************************************
  * File Name          : cmos_tsk.c
  * Description        : Code for freertos applications
  ******************************************************************************
  * @attention
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "bsp.h"
#include "tskcfg.h"
#include "ov2640.h"
#include "cmos.h"

TaskHandle_t xCmos_Thd = NULL;
StaticTask_t xCmos_Tcb;
StackType_t  xCmos_Stk[CMOS_STACK_SIZE];

QueueHandle_t        Cmos_Cmd_qhd = NULL;
static StaticQueue_t cmos_cmd_stru;
static uint8_t       cmos_cmd_area[CMOS_CMD_QUE_LENGTH * CMOS_CMD_QUE_ITEMSIZE];

const Cmos_CmdEnum Cmos_CmdStartCapture = CMOS_CMD_START_CAPTURE;
const Cmos_CmdEnum Cmos_CmdCaptureComplete = CMOS_CMD_CAPTURE_COMPLETE;
const Cmos_CmdEnum Cmos_CmdDcmiError = CMOS_CMD_DCMI_ERROR;
const Cmos_CmdEnum Cmos_CmdDcmiOverrun = CMOS_CMD_DCMI_OVERRUN;
const Cmos_CmdEnum Cmos_CmdOverSize = CMOS_CMD_OVER_SIZE;
const Cmos_CmdEnum Cmos_CmdTransferError = CMOS_CMD_TRANSFER_ERROR;

static inline void ov2640_init(void)
{
  SCCB_BspInit();
  Dcmi_BspInit();
  
  OV2640_ChipReset();
  
  if(OV2640_CheckChipID() != 0)
  {
    SysDbgLog("OV2640 ID Check fail!\r\n");
  }
}

static inline void ov2640_config(void)
{
  OV2640_JPEGConfig(JPEG_320x240);
		OV2640_BrightnessConfig(0x20);	
//		OV2640_AutoExposure(2);	
}

static void cmos_get_photo(Cmos_GetJpegPhoto *photo, const uint8_t *rcvbuf, uint32_t rcvlen)
{
  uint32_t i;
  uint32_t start, end;
  
  if((rcvlen < 5) && (rcvlen > CMOS_PHOTOBUF_MAXLEN))
  {
    photo->photo = NULL;
    photo->photosize = 0;
    return;
  }
  
  for(i=0; i<(rcvlen-1); i++)
  {
    if((rcvbuf[i] == 0xFF) && (rcvbuf[i+1] == 0xD8))
    {
      start = i;
      
      i+=2;
      
      while(i < (rcvlen-1))
      {
        if((rcvbuf[i] == 0xFF) && (rcvbuf[i+1] == 0xD9))
        {
          photo->photo = rcvbuf+start;
          photo->photosize = i - start + 2;
          return;
        }
        
        i++;
      }
      
      photo->photo = NULL;
      photo->photosize = 0;
      return;
    }
  }
  
  photo->photo = NULL;
  photo->photosize = 0;
  return;
}

void vCmos_Task(void * pvParameters)
{
  Cmos_CmdEnum rcmd;
  Cmos_GetJpegPhoto photo;
  
  ov2640_init();
  
  ov2640_config();
  
  Cmos_Cmd_qhd = xQueueCreateStatic(CMOS_CMD_QUE_LENGTH, CMOS_CMD_QUE_ITEMSIZE,
	                                  cmos_cmd_area, &cmos_cmd_stru);
	while(1)
	{
    if(xQueueReceive(Cmos_Cmd_qhd, &rcmd, portMAX_DELAY) == pdTRUE)
    {
      switch(rcmd)
      {
        case CMOS_CMD_START_CAPTURE:
          if((READ_BIT(DCMI->CR, DCMI_CR_ENABLE) == 0) && (READ_BIT(DCMI->CR, DCMI_CR_CAPTURE) == 0))
          {
            Dcmi_StartCapture();
//            SysDbgLog("Cmos start capture...\r\n");
          }
          else
          {
//            SysDbgLog("Cmos capturing......\r\n");
          }
          break;
        
        case CMOS_CMD_CAPTURE_COMPLETE:
          cmos_get_photo(&photo, (const uint8_t *)Cmos_PhotoBuf, (CMOS_PHOTOBUF_MAXLEN - LL_DMA_GetDataLength(DMA2, LL_DMA_CHANNEL_5))*4);
          Tty_Sendbuf(photo.photo, photo.photosize);
          break;
        
        case CMOS_CMD_DCMI_ERROR:
          SysDbgLog("CMOS_CMD_DCMI_ERROR!\r\n");
          break;
        
        case CMOS_CMD_DCMI_OVERRUN:
          SysDbgLog("CMOS_CMD_DCMI_OVERRUN!\r\n");
          break;
        
        case CMOS_CMD_OVER_SIZE:
          SysDbgLog("CMOS_CMD_OVER_SIZE!\r\n");
          break;
        
        case CMOS_CMD_TRANSFER_ERROR:
          SysDbgLog("CMOS_CMD_TRANSFER_ERROR!\r\n");
          break;
        
        default:
          break;
      }
    }
	}
}
